#include "stdafx.h"
#include "HBombs.h"
#include "HBoxPlacerRule.h"
#include "HBoxes.h"
#include "HRoomManager.h"
#include "GameRoom.h"
#include "HGlobalManager.h"

namespace OSLib
{
	template<> BombBox::BombManager* Singleton<BombBox::BombManager>::ms_Singleton = NULL;
}

namespace BombBox
{
	BombItem::BombItem( GameItem_Bomb* pBomb )
		: m_pBomb(pBomb)
	{
		m_pItemController = NULL;
		m_nRotateNum = 0;
	}

	BombItem::~BombItem( void )
	{
	}

	void BombItem::setItemController( ItemController* pItemController )
	{
		m_pItemController = pItemController;
	}

	const char* BombItem::getItemName( void )
	{
		if( m_pBomb == NULL ) return NULL;
		return m_pBomb->getFile().c_str();
	}

	bool BombItem::enableLight( int nStatus )
	{
		return false;
	}

	irr::core::stringc BombItem::getItemMesh( int nStatus )
	{
		return m_pBomb->getFile();
	}

	irr::core::stringc BombItem::getItemPath( int nStatus )
	{
		return m_pBomb->getPath();
	}

	bool BombItem::getStatusAnimation( int nStatus )
	{
		return false;
	}

	void BombItem::onAnimationStop( int nStatus )
	{
		//::OutputDebugStringA("Bomb:animatin stoped\n");
		s_pBoxPlacerRuler->doBomb(this);
	}

	int BombItem::getAnimationSpeed( int nStatus )
	{
		return 1000;
	}

	void BombItem::doBomb( int x, int y, int z, int nDist )
	{
		if( m_pBomb == NULL ) return;

		GameRoom* pRoom = s_pRoomManager->getActiveRoom();
		RoomController* pRoomController = pRoom->getController();
		if( pRoomController == NULL ) return;

		BoxItem* pBox =  dynamic_cast<BoxItem*>(s_pBoxPlacerRuler->getGameItem( x, y, z ));
		
		if( pBox == NULL ) return;

		int nValue1, nValue2;
		if( m_pBomb->getDamage( pBox->getType(), nValue1, nValue2 ) == false ) return;

		if( nDist == 2 ) nValue1 = nValue2;

		if( pBox )
		{
			if (pBox->doDamage( nValue1 ))
			{
				pRoomController->removeItem(pBox);
				s_pBoxPlacerRuler->onBoxBomb( x, y, z );
			}
		}
	}

	void BombItem::doBomb( void )
	{
		if( m_pBomb == NULL ) return;

		switch( m_pBomb->getType() )
		{
		case EBT_AROUND:doBomb_Around();break;
		case EBT_CROSS:doBomb_Cross();break;
		case EBT_CUBE:doBomb_Cube();break;
		case EBT_DIRECT:doBomb_Direct();break;
		case EBT_DOWN:doBomb_Down();break;
		case EBT_UP:doBomb_Up();break;
		default :;
		}
	}

	void BombItem::doBomb_Cross( )
	{
		irr::core::vector3df vPos = getPosition(0);
		int ix,iy,iz;
		if( !BOXUTIL::grid(vPos.X, vPos.Y, vPos.Z, ix, iy, iz) ) return;

		doBomb( ix, iy, iz + 1, 1 );
		doBomb( ix, iy, iz - 1, 1 );
		doBomb( ix + 1, iy, iz, 1 );
		doBomb( ix - 1, iy, iz, 1 );

		if( m_pBomb->getDist() == 2 )
		{
			doBomb( ix, iy, iz + 2, 2 );
			doBomb( ix, iy, iz - 2, 2 );
			doBomb( ix + 2, iy, iz, 2 );
			doBomb( ix - 2, iy, iz, 2 );
		}
	}

	void BombItem::doBomb_Around( void )
	{
		irr::core::vector3df vPos = getPosition(0);
		int ix,iy,iz;
		if( !BOXUTIL::grid(vPos.X, vPos.Y, vPos.Z, ix, iy, iz) ) return;

		doBomb( ix, iy, iz + 1, 1 );
		doBomb( ix, iy, iz - 1, 1 );
		doBomb( ix + 1, iy, iz, 1 );
		doBomb( ix - 1, iy, iz, 1 );

		doBomb( ix + 1, iy, iz + 1, 1 );
		doBomb( ix - 1, iy, iz + 1, 1 );
		doBomb( ix + 1, iy, iz - 1, 1 );
		doBomb( ix - 1, iy, iz - 1, 1 );

		if( m_pBomb->getDist() == 2 )
		{
			doBomb( ix, iy, iz + 2, 2 );
			doBomb( ix, iy, iz - 2, 2 );
			doBomb( ix + 2, iy, iz, 2 );
			doBomb( ix - 2, iy, iz, 2 );

			doBomb( ix + 2, iy, iz + 2, 2 );
			doBomb( ix - 2, iy, iz + 2, 2 );
			doBomb( ix + 2, iy, iz - 2, 2 );
			doBomb( ix - 2, iy, iz - 2, 2 );
		}
	}

	void BombItem::doBomb_Cube( void )
	{
		irr::core::vector3df vPos = getPosition(0);
		int ix,iy,iz;
		if( !BOXUTIL::grid(vPos.X, vPos.Y, vPos.Z, ix, iy, iz) ) return;

		doBomb( ix, iy, iz + 1, 1 );
		doBomb( ix, iy, iz - 1, 1 );
		doBomb( ix + 1, iy, iz, 1 );
		doBomb( ix - 1, iy, iz, 1 );
		doBomb( ix + 1, iy, iz + 1, 1 );
		doBomb( ix - 1, iy, iz + 1, 1 );
		doBomb( ix + 1, iy, iz - 1, 1 );
		doBomb( ix - 1, iy, iz - 1, 1 );

		doBomb( ix, iy + 1, iz + 1, 1 );
		doBomb( ix, iy + 1, iz - 1, 1 );
		doBomb( ix + 1, iy + 1, iz, 1 );
		doBomb( ix - 1, iy + 1, iz, 1 );
		doBomb( ix + 1, iy + 1, iz + 1, 1 );
		doBomb( ix - 1, iy + 1, iz + 1, 1 );
		doBomb( ix + 1, iy + 1, iz - 1, 1 );
		doBomb( ix - 1, iy + 1, iz - 1, 1 );

		doBomb( ix, iy - 1, iz + 1, 1 );
		doBomb( ix, iy - 1, iz - 1, 1 );
		doBomb( ix + 1, iy - 1, iz, 1 );
		doBomb( ix - 1, iy - 1, iz, 1 );
		doBomb( ix + 1, iy - 1, iz + 1, 1 );
		doBomb( ix - 1, iy - 1, iz + 1, 1 );
		doBomb( ix + 1, iy - 1, iz - 1, 1 );
		doBomb( ix - 1, iy - 1, iz - 1, 1 );

		if( m_pBomb->getDist() == 2 )
		{
			doBomb( ix, iy, iz + 2, 2 );
			doBomb( ix, iy, iz - 2, 2 );
			doBomb( ix + 2, iy, iz, 2 );
			doBomb( ix - 2, iy, iz, 2 );
			doBomb( ix + 2, iy, iz + 2, 2 );
			doBomb( ix - 2, iy, iz + 2, 2 );
			doBomb( ix + 2, iy, iz - 2, 2 );
			doBomb( ix - 2, iy, iz - 2, 2 );

			doBomb( ix, iy + 2, iz + 2, 2 );
			doBomb( ix, iy + 2, iz - 2, 2 );
			doBomb( ix + 2, iy + 2, iz, 2 );
			doBomb( ix - 2, iy + 2, iz, 2 );
			doBomb( ix + 2, iy + 2, iz + 2, 2 );
			doBomb( ix - 2, iy + 2, iz + 2, 2 );
			doBomb( ix + 2, iy + 2, iz - 2, 2 );
			doBomb( ix - 2, iy + 2, iz - 2, 2 );

			doBomb( ix, iy - 2, iz + 2, 2 );
			doBomb( ix, iy - 2, iz - 2, 2 );
			doBomb( ix + 2, iy - 2, iz, 2 );
			doBomb( ix - 2, iy - 2, iz, 2 );
			doBomb( ix + 2, iy - 2, iz + 2, 2 );
			doBomb( ix - 2, iy - 2, iz + 2, 2 );
			doBomb( ix + 2, iy - 2, iz - 2, 2 );
			doBomb( ix - 2, iy - 2, iz - 2, 2 );
		}
	}
	
	void BombItem::doBomb_Direct( void )
	{
		irr::core::vector3df vPos = getPosition(0);
		int ix,iy,iz;
		if( !BOXUTIL::grid(vPos.X, vPos.Y, vPos.Z, ix, iy, iz) ) return;

		switch( m_nRotateNum )
		{
		case 0:doBomb( ix, iy, iz + 1, 1 );break;
		case 1:doBomb( ix - 1, iy, iz, 1 );break;
		case 2:doBomb( ix, iy, iz - 1, 1 );break;
		case 3:doBomb( ix + 1, iy, iz, 1 );break;
		default:;
		}

		if( m_pBomb->getDist() == 2 )
		{
			switch( m_nRotateNum )
			{
			case 0:doBomb( ix, iy, iz + 2, 2 );break;
			case 1:doBomb( ix - 2, iy, iz, 2 );break;
			case 2:doBomb( ix, iy, iz - 2, 2 );break;
			case 3:doBomb( ix + 2, iy, iz, 2 );break;
			default:;
			}
		}
		
	}
	
	void BombItem::doBomb_Down( void )
	{
		irr::core::vector3df vPos = getPosition(0);
		int ix,iy,iz;
		if( !BOXUTIL::grid(vPos.X, vPos.Y, vPos.Z, ix, iy, iz) ) return;

		doBomb( ix, iy - 1, iz, 1 );

		if( m_pBomb->getDist() == 2 )
		{
			doBomb( ix, iy - 2, iz, 2 );
		}
	}
	
	void BombItem::doBomb_Up( void )
	{
		irr::core::vector3df vPos = getPosition(0);
		int ix,iy,iz;
		if( !BOXUTIL::grid(vPos.X, vPos.Y, vPos.Z, ix, iy, iz) ) return;

		doBomb( ix, iy + 1, iz, 1 );

		if( m_pBomb->getDist() == 2 )
		{
			doBomb( ix, iy + 2, iz, 2 );
		}
	}

	void BombItem::toggleRotate( void )
	{
		m_nRotateNum = (m_nRotateNum+1)%4;
	}

	int BombItem::getType()
	{
		if( m_pBomb == NULL ) return -1;
		return m_pBomb->getType();
	}

	///////////////////////////////////////////////////////////////////////////////

	GameItem_Bomb::GameItem_Bomb( void )
	{
		m_sItem0 = "";
		m_sFilePath = "";
	}

	GameItem_Bomb::~GameItem_Bomb( void )
	{
	}

	void GameItem_Bomb::setPath( irr::core::stringc sPath )
	{
		m_sFilePath = sPath;
	}

	void GameItem_Bomb::setFile( irr::core::stringc sFile )
	{
		m_sItem0 = sFile;
	}
	
	void GameItem_Bomb::setID( int nID )
	{
		m_nID = nID;
	}

	void GameItem_Bomb::setType( int nType )
	{
		m_nType = nType;
	}
	
	void GameItem_Bomb::addBombDamage( int nTargetID, int nValue1, int nValue2 )
	{
		m_nDamageValue[nTargetID] = BombDamage(nTargetID,nValue1,nValue2);
	}

	void GameItem_Bomb::setDist( int nDist )
	{
		m_nDist = nDist;
	}

	BombItem* GameItem_Bomb::createInstance( void )
	{
		BombItem* pBomb = new BombItem( this );
		return pBomb;
	}

	irr::core::stringc GameItem_Bomb::getFile( void )
	{
		return m_sItem0;
	}

	irr::core::stringc GameItem_Bomb::getPath( void )
	{
		return m_sFilePath;
	}
	
	int GameItem_Bomb::getID( void )
	{
		return m_nID;
	}
	
	int GameItem_Bomb::getType( void )
	{
		return m_nType;
	}
	
	int GameItem_Bomb::getDist( void )
	{
		return m_nDist;
	}
	
	bool GameItem_Bomb::getDamage( int nTarget, int& nValue1, int& nValue2 )
	{
		irr::core::map<int,BombDamage>::Node* pNode = m_nDamageValue.find( nTarget );
		
		if( pNode == 0 )
		{
			nValue1 = nValue2 = 0;
			return false;
		}

		nValue1 = pNode->getValue().m_nValue1;
		nValue2 = pNode->getValue().m_nValue2;
		return true;
	}
	///===================================================================
	BombManager::BombManager()
	{
	}

	BombManager::~BombManager()
	{
	}

	void BombManager::loadConfig( irr::core::stringc sFile )
	{
		irr::io::IFileSystem* fileSys = s_pGlobalManager->getFileSystem();
		irr::io::IXMLReader* pReader = fileSys->createXMLReader( sFile );

		GameItem_Bomb* pBombItem = NULL;

		while(pReader && pReader->read())
		{
			switch(pReader->getNodeType())
			{
			case irr::io::EXN_ELEMENT:
				{
					if(irr::core::stringw("Bomb") == pReader->getNodeName())
					{
						pBombItem = NULL;

						int nID = pReader->getAttributeValueAsInt(L"ID");
						irr::core::stringc sFilePath = pReader->getAttributeValue(L"File");
						int nScope = pReader->getAttributeValueAsInt(L"Scope");
						int nDist = pReader->getAttributeValueAsInt(L"Dist");

						if( nDist != 1 && nDist != 2 ) continue;
						if( nID <=0 ) continue;
						
						pBombItem = registerBox( nID );

						pBombItem->setFile( sFilePath );
						pBombItem->setDist( nDist );
						pBombItem->setType( nScope );
					}

					if(irr::core::stringw("Damage") == pReader->getNodeName())
					{
						if( pBombItem == NULL ) continue;

						int nTarget = pReader->getAttributeValueAsInt(L"Target");
						int nValue1 = pReader->getAttributeValueAsInt(L"Value1");
						int nValue2 = pReader->getAttributeValueAsInt(L"Value2");
						
						pBombItem->addBombDamage( nTarget, nValue1, nValue2 );
					}
					break;
				}
			}
		}
	}
	
	GameItem_Bomb* BombManager::registerBox( int nTypeID )
	{
		if( m_vBombs.find(nTypeID) == 0 )
		{
			GameItem_Bomb* pBomb = new GameItem_Bomb();
			pBomb->setID( nTypeID );

			m_vBombs[ nTypeID ] = pBomb;
		}
			
		return m_vBombs[nTypeID];
	}

	BombItem* BombManager::createBomb( int nTypeID )
	{
		irr::core::map<int,GameItem_Bomb*>::Node* pNode = m_vBombs.find(nTypeID);
		if( pNode == 0 ) return NULL;
		return pNode->getValue()->createInstance();
	}
}